# -*- coding: utf-8 -*-

import datetime
from django.test import TestCase, Client
from django.db.models import Q, Max
from django.http import Http404
from django.core.urlresolvers import reverse

from base import FilledDbTestCase, LeanDbTestCase

from stream.views import namesToPath, pathToNames
from stream import models, views, feeds, forms, utils

import feedprovider

try:
    import json
except:
    import simplejson as json

def getLoggedUserId(client):
    # Look @ django.test.Client and django.contrib.auth
    from django.contrib.auth import SESSION_KEY
    if SESSION_KEY in client.session:
        return client.session[SESSION_KEY]
    else:
        return None

class TestLogin(LeanDbTestCase):
    def testLoginDisplay(self):
        self.login(self.openid1)
        response = self.client.get('/', follow = True)
        self.assertContains(response, self.user1.get_profile().display_name)

    def testLogoutInternal(self):
        self.login(self.openid1)
        self.client.logout()
        self.assertTrue(getLoggedUserId(self.client) is None)

    def testLogoutRequest(self):
        self.login(self.openid1)
        response = self.client.get('/logout', follow = True)
        self.assertTrue(getLoggedUserId(self.client) is None)
        self.assertTemplateUsed(response, 'stream/root.html')

class TestFetch(FilledDbTestCase):
    def filterByLink(self, entry_list, link):
        return filter(lambda x: x.get('entry') and x.get('entry').get('link') == link, entry_list)

    def testOwnEntries(self):
        self.login(self.openid1)
        response = self.client.get('/getEntries/?owner_id=%s' % self.user1.id)
        response_data = json.loads(response.content)
        google_data = self.filterByLink(response_data, self.google_entry.link)
        entry = google_data[0]['entry']
        self.assertEqual(entry['link'], self.google_entry.link)
        self.assertEqual(entry['created'], '2009-09-10 00:00:00')
        self.assertEqual(google_data[0]['published'], False)
        self.assertTagListEqual(google_data[0]['tags'], [{'name' : 'google'}, {'name' : 'search'}])

    def testIgnored(self):
        self.login(self.openid1)
        self.google_message.ignored = True
        self.google_message.save()
        response = self.client.get('/getEntries/?owner_id=%s' % self.user1.id)
        response_data = json.loads(response.content)
        self.assertTrue(self.google_message.id not in map(lambda x: x['id'], response_data))

    def testSubscriptions(self):
        self.login(self.openid1)
        response = self.client.get('/getEntries/?owner_id=%s&subscription=%s' % (self.user1.id, self.feed_subscription1.id))
        response_data = json.loads(response.content)
        self.assertTrue(len(response_data) > 0)

    def testOtherEntries(self):
        def doTest():
            response = self.client.get('/getEntries/?owner_id=%s' % self.user2.id)
            response_data = json.loads(response.content)
            cpp_data = self.filterByLink(response_data, self.cpp_entry.link) # This is not published
            self.assertEqual(len(cpp_data), 0)
            yahoo_data = self.filterByLink(response_data, self.yahoo_entry.link)
            entry = yahoo_data[0]['entry']
            self.assertEqual(entry['link'], self.yahoo_entry.link)
            self.assertEqual(entry['created'], '2009-09-10 00:00:00')
            self.assertEqual(yahoo_data[0]['published'], True)
            self.assertEqual(yahoo_data[0]['tags'], [{'name' : 'search'}, {'name' : 'yahoo'}])

        self.login(self.openid1)
        doTest()
        self.client.logout()   # Anonymous user must get the same results as any other non-owner
        doTest()

    def testOwnTags(self):
        self.login(self.openid1)
        response = self.client.get('/getTags/?owner_id=%s' % self.user1.id)
        response_data = json.loads(response.content)
        self.assertTrue(utils.unorderedEqual(response_data, [ {'name' : 'google', 'count' : 1}, {'name' : 'search', 'count' : 1}, {'name' : 'c++', 'count' : 1}]))

    def testOtherTags(self):
        def doTest():
            response = self.client.get('/getTags/?owner_id=%s' % self.user2.id)
            response_data = json.loads(response.content)
            self.assertTrue(utils.unorderedEqual(response_data, [{'name' : 'search', 'count' : 1}, {'name' : 'yahoo', 'count' : 1}]))

        self.login(self.openid1)
        doTest()
        self.client.logout()
        doTest()

class FetchLimitsTest(LeanDbTestCase):
    def setUp(self):
        super(FetchLimitsTest, self).setUp()
        self.links = ['http://link1', 'http://link2', 'http://link3']
        entries = [models.BookmarkEntry.objects.create(created = datetime.datetime(2010, 01, 01, 0, 0, 0), link = self.links[0]),
            models.BookmarkEntry.objects.create(created = datetime.datetime(2010, 01, 02, 0, 0, 0), link = self.links[1]),
            models.BookmarkEntry.objects.create(created = datetime.datetime(2010, 01, 03, 0, 0, 0), link = self.links[2])]
        for entry in entries:
            models.Message.objects.create(entry = entry, user = self.user1)

    def testPresentLimits(self):
        self.login(self.openid1)
        response = self.client.get(reverse('stream.views.entries'), { 'first' : 1, 'count' : 1})
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        self.assertEqual(len(response_data), 1)
        self.assertEqual(response_data[0]['entry']['link'], self.links[1])

    def testOmittedLimits(self):
        self.login(self.openid1)
        response = self.client.get(reverse('stream.views.entries'))
        self.assertEqual(response.status_code, 200)
        response_data = json.loads(response.content)
        self.assertEqual(len(response_data), 3)

class SubscriptionFetchTest(LeanDbTestCase):
    def testSubscription(self):
        entries = [models.BookmarkEntry.objects.create(created = datetime.datetime(2010, 01, 01, 0, 0, 0), link = 'http://link1'),
            models.BookmarkEntry.objects.create(created = datetime.datetime(2010, 01, 02, 0, 0, 0), link = 'http://link2')]
        # Need a stub channel to create a subscription.
        channel = models.DeliciousChannel.objects.create(author = 'author')
        subscription = channel.createSubscription(user = self.user1)[0]
        messages = [subscription.createMessage(entry) for entry in entries]
        messages[0].read = True
        messages[0].save()
        self.login(self.openid1)
        response = self.client.get(reverse('stream.views.subscriptions'))
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]['id'], subscription.id)
        self.assertEqual(data[0]['unread'], 1)

    def testEmptySubscription(self):
        channel = models.DeliciousChannel.objects.create(author = 'author')
        subscription = channel.createSubscription(user = self.user1)[0]
        self.login(self.openid1)
        response = self.client.get(reverse('stream.views.subscriptions'))
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]['id'], subscription.id)
        self.assertEqual(data[0]['unread'], 0)

class TestDisplay(LeanDbTestCase):
    """
    Checks that users see only what they should.
    """
    def testNonExistentUser(self):
        """
        Must get a 404 when asking for unknown user.
        """
        self.login(self.openid1)
        from django.contrib.auth.models import User
        big_id = User.objects.aggregate(max = Max('id'))['max'] + 1
        response = self.client.get('/%s' % big_id)
        self.assertEqual(response.status_code, 404)

    def testAnonymousBrowse(self):
        response = self.client.get('/%s' % self.user1.id)
        self.assertEqual(response.status_code, 200)

class TestEdit(FilledDbTestCase):
    def testPublish(self):
        self.login(self.openid1)

        id = self.google_message.id
        old_tags = self.google_message.tags.all();
        new_tags = 'my tags';
        self.client.post(reverse('stream.views.editMessage'), {'id' : str(id), 'published' : 'true'})
        message = models.Message.objects.get(id = id)
        self.assertEqual(True, message.published)
        self.assertTagListEqual(old_tags, message.tags.all())
        self.client.post(reverse('stream.views.editMessage'), {'id' : str(id), 'tags' : new_tags})
        message = models.Message.objects.get(id = id)
        self.assertEqual(True, message.published)
        self.assertTagListEqual(['my', 'tags'], message.tags.all())

        self.client.post(reverse('stream.views.editMessage'), { 'id' : str(id), 'read' : utils.urlRepresentation(True) })
        message = models.Message.objects.get(id = id)
        self.assertEqual(True, message.read)

class TestAdd(LeanDbTestCase):
    """
    Entry addition.
    """
    def setUp(self):
        super(TestAdd, self).setUp()
        self.command0_livejournal_link = 'http://command0.livejournal.com/data/rss'
        self.feed_provider.data_dict.update(feedprovider.lj_data)

    def testNewEntryAdd(self):
        self.login(self.openid1)
        link = u'http://rambler.ru/'
        tag_list = ['rambler', 'search']
        # TODO: This looks like coupling URLConfig with application, but who cares
        response = self.client.post('/add', { 'form_name' : forms.BookmarkForm._meta.FORM_NAME, 'link' : link, 'tags' : ' '.join(tag_list) })
        entry = models.BookmarkEntry.objects.get(link=link)
        self.assertEqual(entry.message_set.count(),  1)
        self.assertTrue(entry)
        message = entry.message_set.all()[0]
        self.assertTagListEqual(tag_list, message.tags.all())

    def testBadEntryAdd(self):
        """
        Adding bad URL will lead to back to add page with the entered data still there
        """
        self.login(self.openid1)
        link = u'someshit'
        tags = u'other shit'
        response = self.client.post('/add', { 'form_name' : forms.BookmarkForm._meta.FORM_NAME, 'link' : link, 'tags' : tags }, follow=True)
        self.assertEqual(response.status_code, 200)
        bookmark_form = response.context['form']
        self.assertTrue(isinstance(bookmark_form, forms.BookmarkForm))
        self.assertEqual(bookmark_form['link'].data, link)
        self.assertEqual(bookmark_form['tags'].data, tags)

    def testFeedAdd(self):
        feeds.find_feed.mock(utils.identity)
        feeds.retrieve_feed.mockValue(feeds.feedparser.parse(open('stream/testcases/django_rss.xml').read()))
        feed_url = 'http://djangoproject.com/weblog'
        channel = models.FeedChannel.get_or_create(url = feed_url)
        subscription = channel.createSubscription(user = self.user1)[0]
        feed_channel = subscription.channel.feedchannel

        self.assertEqual(feed_channel.subscription_set.count(),  1)
        subscription = feed_channel.subscription_set.all()[0]
        self.assertEqual(feed_channel.title, subscription.name)
        # Add checks for messages here. Too lazy now.

    def testFeedAddClient(self):
        self.login(self.openid1)
        feeds.find_feed.mock(utils.identity)
        feed_url = 'http://djangoproject.com/weblog'
        feeds.retrieve_feed.mockValue(feeds.feedparser.parse(open('stream/testcases/django_rss.xml').read()))
        response = self.client.post('/add', { 'form_name' : forms.FeedUrlForm._meta.FORM_NAME, 'url' : feed_url })
        data = json.loads(response.content)
        self.assertEqual(data['status'], 'success')
        subscription = models.Subscription.objects.get(channel__feedchannel__link = feed_url) #Should return correctly
        self.assertTrue(subscription.message_set.count() > 0)

    def testNonExistentFeed(self):
        self.login(self.openid1)
        response = self.client.post('/add', { 'form_name' : forms.FeedUrlForm._meta.FORM_NAME, 'url' : 'http://some_url' }, follow = True)
        self.assertEqual(response.status_code, 200)
        feed_form = response.context['form']
        self.assertTrue(isinstance(feed_form, forms.FeedUrlForm))
        self.assertEqual(len(feed_form.errors['url']), 1)

    def createSubscription(self, user, import_tags = False, published = False, tags = []):
        self.login(user.useropenid_set.all()[0].claimed_id)
        response = self.client.post('/add', { 'form_name' : forms.FeedUrlForm._meta.FORM_NAME, 'url' : self.command0_livejournal_link, 'import_tags' : utils.urlRepresentation(import_tags), 'published' : utils.urlRepresentation(published), 'tags' : namesToPath(tags) }, follow = True)
        self.assertEqual(response.status_code, 200)
        subscription = models.Subscription.objects.get(channel__feedchannel__link = self.command0_livejournal_link, user = user)
        self.assertEqual(subscription.import_tags, import_tags)
        return subscription

    def testImportTags(self):
        self.lj_channel = models.FeedChannel.get_or_create(url = self.command0_livejournal_link)

        subscription = self.createSubscription(self.user1, import_tags = False)
        for message in subscription.message_set.all():
            self.assertEqual(message.tags.count(), 0)

        subscription = self.createSubscription(self.user2, import_tags = True)
        message = subscription.message_set.get(entry__feedentry__title = 'SSD')
        self.assertTrue(utils.unorderedEqual(map(lambda x: x.name, message.tags.all()), [u'комп', u'апгрейд']))

    def testTags(self):
        self.lj_channel = models.FeedChannel.get_or_create(url = self.command0_livejournal_link)
        tag_list = ['my', 'lj']

        subscription = self.createSubscription(self.user1, import_tags = False, tags = tag_list)
        self.assertTagListEqual(subscription.tags.all(), tag_list)

    def testPublished(self):
        self.lj_channel = models.FeedChannel.get_or_create(url = self.command0_livejournal_link)

        subscription = self.createSubscription(self.user1, published = False)
        self.assertEqual(subscription.published, False)

        subscription = self.createSubscription(self.user2, published = True)
        self.assertEqual(subscription.published, True)

class TaggedMessages(FilledDbTestCase):
    """
    Selecting messages with given tags
    """
    def checkRetrievedEntriesForTags(self, tag_list, response):
        query_list = map(lambda x: Q(tags__name = x), tag_list)
        entries_from_db = models.Message.objects.all()
        for tag in tag_list:
            entries_from_db = entries_from_db.filter(tags__name = tag)
        def getLinks(sequence):
            return map(lambda x: x.entry.bookmarkentry.link, sequence)
        for link in getLinks(entries_from_db):
            self.assertContains(response, link)

    def testAlphaTagRequest(self):
        """
        Test passing tags in POST request.
        """
        self.login(self.openid1)
        tag_list = ['search', 'google']
        response = self.client.get('/getEntries', { 'tags' : ' '.join(tag_list) }, follow=True)
        self.checkRetrievedEntriesForTags(tag_list, response)

    def testTagRequestWithPlus(self):
        """
        Check that we really retrieve entries for non-alphanumeric tags
        """
        self.login(self.openid1)
        response = self.client.get('/getEntries', { 'tags' : ['c++'] }, follow=True)
        self.assertContains(response, 'cplusplus')

class SubscriptionSettingsTest(LeanDbTestCase):
    """
    Test subscription settings and filters.
    """
    def setUp(self):
        """
        Create a subscription from user1 to user2 to play with.
        """
        super(SubscriptionSettingsTest, self).setUp()
        self.login(self.openid1)
        self.client.post('/subscribe', { 'id' : self.user2.id, 'tags': '' })
        self.subscription = models.Subscription.objects.all().order_by('-id')[0]

    def testEditing(self):
        new_name = 'ololo'
        new_published = True
        new_tags = ['megalol']
        response = self.client.post('/subscriptionEdit',  { 'id' : self.subscription.id, 'name' : new_name, 'published' : 'true', 'tags' : ' '.join(new_tags), 'update' : 'false' }, follow = True)
        self.assertEqual(response.status_code, 200)
        subscription = models.Subscription.objects.get(id = self.subscription.id)
        self.assertEqual(subscription.name, new_name)
        self.assertEqual(subscription.published, new_published)
        self.assertTagListEqual(new_tags, subscription.tags.all())

        self.login(self.openid2)
        response = self.client.post('/add', { 'form_name' : forms.BookmarkForm._meta.FORM_NAME, 'link' : 'http://example.com', 'tags' : [], 'published' : 'true' }, follow = True)
        self.assertEqual(response.status_code, 200)
        message = models.Message.objects.all().order_by('-id')[0]
        self.assertEqual(self.user1.id, message.user.id)
        self.assertEqual(subscription.id, message.subscriptions.all()[0].id)
        self.assertEqual(message.published, new_published)
        self.assertTagListEqual(new_tags, message.tags.all())

    def testMessageUpdating(self):
        new_published = True
        new_tags = ['megalol']
        response = self.client.post('/subscriptionEdit',  { 'id' : self.subscription.id, 'name' : self.subscription.name, 'published' : 'true', 'tags' : ' '.join(new_tags), 'update' : 'true' }, follow = True)
        messages = models.Message.objects.filter(subscriptions__id = self.subscription.id)
        for message in messages:
            self.assertEqual(message.published, new_published)
            message_tag_set = set(map(lambda x: x.name, message.tags.all()))
            new_tag_set = set(new_tags)
            self.assertTrue(new_tag_set.issubset(message_tag_set))

class UserSubscriptitonTest(FilledDbTestCase):
    """
    Subscribing to other users.
    """
    def testSubscribeToTag(self):
        self.login(self.openid1)
        tag_list = ['yahoo']
        response = self.client.post('/subscribe', { 'id' : self.user2.id, 'tags': ' '.join(tag_list) })
        yahoo_message = models.Message.objects.get(user__id = self.user1.id, entry__id = self.yahoo_entry.id)

        #Subscribe one more time to this channel, no more subscriptions should be added
        subscription_count = models.Subscription.objects.count()
        response = self.client.post('/subscribe', { 'id' : self.user2.id, 'tags': ' '.join(tag_list) })
        self.assertEqual(subscription_count, models.Subscription.objects.count())

        #Subscribe to one more channel with this entry, it shouldn't be added another time
        tag_list = ['search']
        response = self.client.post('/subscribe', { 'id' : self.user2.id, 'tags': ' '.join(tag_list) })
        yahoo_message = models.Message.objects.get(user__id = self.user1.id, entry__id = self.yahoo_entry.id)

class DeliciousSubscriptionTest(LeanDbTestCase):
    def setUp(self):
        super(DeliciousSubscriptionTest, self).setUp()
        self.feed_provider.data_dict.update(feedprovider.delicious_data)
        models.DeliciousChannel.retrieveUrl.mock(self.feed_provider.retrieve_feed)

    def testSubscribe(self):
        self.login(self.openid1)
        response = self.client.post('/add', { 'form_name' : forms.DeliciousForm._meta.FORM_NAME, 'author' : 'command0', 'import_tags' : utils.urlRepresentation(True) }, follow = True)
        self.assertEqual(response.status_code, 200)
        response = self.client.get('/getEntries', { 'owner_id' : self.user1.id })
        data = json.loads(response.content)
        data = filter(lambda x: x['entry']['link'].find('delicious.com') != -1, data)[0]
        self.assertEqual(data['entry']['link'], "http://delicious.com/help/feeds")
        self.assertEqual(data['entry']['title'], "delicious/help/feeds")
        self.assertTrue(utils.unorderedEqual(data['tags'], [{ "name" : "delicious" }, { "name" : "feeds" }, { "name" :"diploma" }]))

    def testSubscribeNonExistent(self):
        self.login(self.openid1)
        response = self.client.post('/add', { 'form_name' : forms.DeliciousForm._meta.FORM_NAME, 'author' : 'aaaaa' }, follow = True)
        self.assertEqual(response.status_code, 200)
        delicious_form = response.context['form']
        self.assertTrue(isinstance(delicious_form, forms.DeliciousForm))
        self.assertEqual(len(delicious_form.errors['author']), 1)

    def tearDown(self):
        models.DeliciousChannel.retrieveUrl.reset()

class TwitterSubscriptionTest(LeanDbTestCase):
    def testSubscribe(self):
        self.feed_provider.data_dict.update(feedprovider.twitter_data)
        self.login(self.openid1)
        models.TwitterChannel.retrieveUrl.mock(self.feed_provider.retrieve_feed)
        response = self.client.post('/add', { 'form_name' : forms.TwitterForm._meta.FORM_NAME, 'author' : 'command000', 'import_tags' : utils.urlRepresentation(True) }, follow = True)
        self.assertEqual(response.status_code, 200)
        response = self.client.get('/getEntries', { 'owner_id' : self.user1.id })
        data = json.loads(response.content)
        data = filter(lambda x: ('description' in x['entry']) and x['entry']['description'].find('voted') != -1, data)[0]
        self.assertEqual(data['entry']['link'], "http://twitter.com/command000/statuses/4343309143")
        self.assertEqual(data['entry']['description'], u'I just voted for "Provider logos with licensing\u2026" what do you think? http://uservoice.com/a/VAoU9 #OpenID #feedback')
        self.assertTrue(utils.unorderedEqual(data['tags'], [{ "name" : "OpenID" }, { "name" : "feedback" }]))

class OpmlTest(FilledDbTestCase):
    def testOpml(self):
        self.feed_provider.data_dict.update(feedprovider.lj_data)
        self.login(self.openid1)
        old_channel_count = models.FeedChannel.objects.count()
        opml_data = open('stream/testcases/data/opml.xml')
        response = self.client.post('/add', { 'form_name' : forms.OpmlForm._meta.FORM_NAME, 'file' : opml_data, 'import_tags' : utils.urlRepresentation(True), 'published' : utils.urlRepresentation(True), 'tags' : 'opml' }, follow = True)
        opml_data.close()
        self.assertEqual(response.status_code, 200)

        new_channel_count = models.FeedChannel.objects.count()
        self.assertEqual(old_channel_count + 1, new_channel_count)

        new_channel = models.FeedChannel.objects.get(link = 'http://command0.livejournal.com/data/rss')
        self.assertEqual(new_channel.subscription_set.count(), 1)
        subscription = new_channel.subscription_set.all()[0]
        self.assertEqual(subscription.user, self.user1)
        self.assertEqual(subscription.name, 'My blog')
        self.assertEqual(subscription.published, True)
        self.assertTagListEqual(['opml'], subscription.tags.all())

        new_channel = models.FeedChannel.objects.get(link = 'http://feeds.feedburner.com/codinghorror')
        self.assertNotEqual(new_channel.title, 'One more blog')
        self.assertEqual(new_channel.subscription_set.count(), 2)
        subscription = new_channel.subscription_set.get(user = self.user1)
        self.assertEqual(subscription.name, 'One more blog')
        self.assertTagListEqual(['opml'], subscription.tags.all())

        old_channel = models.FeedChannel.objects.get(link = self.russian_channel.link)
        self.assertEqual(old_channel.subscription_set.count(), 1)

    def testNonExistent(self):
        self.feed_provider.data_dict.update(feedprovider.lj_data)
        self.login(self.openid1)
        old_channel_count = models.FeedChannel.objects.count()
        opml_data = open('stream/testcases/data/bad_opml.xml')
        response = self.client.post('/add', { 'form_name' : forms.OpmlForm._meta.FORM_NAME, 'file' : opml_data }, follow = True)
        self.assertEqual(response.status_code, 200)
        new_channel_count = models.FeedChannel.objects.count()
        self.assertEqual(old_channel_count + 1, new_channel_count)

class RecommendationsTest(FilledDbTestCase):
    def testSimple(self):
        self.login(self.openid1)
        response = self.client.get('/searchUsersData')
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertEqual(len(data), 1)
        self.assertEqual(data[0]['user']['id'], self.user2.id)
        self.assertEqual(data[0]['user']['display_name'],'User Two')
        self.assertEqual(data[0]['tags'], ['search'])

class FilterTest(LeanDbTestCase):
    from stream import morphology
    def setUp(self):
        super(FilterTest, self).setUp()
        self.feed_provider.data_dict.update(feedprovider.lj_data)
        self.lj_channel = models.FeedChannel.get_or_create(url = 'http://command0.livejournal.com/data/rss')
        self.subscription = self.lj_channel.createSubscription(self.user1)[0]

    def applyFilter(self, channel, filter_object):
        entries = map(lambda x: x.promote(), channel.entries.all())
        filtered_entries = filter(lambda x: filter_object.processEntry(x)[0], entries)
        return filtered_entries

    def testRussian(self):
        """
        Search in Russian language.
        """
        self.word = models.Word.objects.create(name = FilterTest.morphology.getWordBase(u'барракуда'))

        filter_object = models.Filter.objects.create(condition_type = 'any', filter_type = 'include', subscription = self.subscription)
        filter_object.words.add(self.word)
        filter_object.save()
        filtered_entries = self.applyFilter(self.lj_channel, filter_object)
        self.assertEqual(1, len(filtered_entries))
        self.assertTrue(filtered_entries[0].description.startswith(u'В рамках'))

    def testTagging(self):
        # Need some setup stuff to create entries and be able to run filters.
        self.login(self.openid1)
        word1 = models.Word.objects.create(name = FilterTest.morphology.getWordBase(u'javascript'))
        word2 = models.Word.objects.create(name = FilterTest.morphology.getWordBase(u'selenium'))
        first_title = 'ActionScript'
        second_title = 'Selenium'

        filter_object = models.Filter.objects.create(condition_type = 'any', filter_type = 'include', subscription = self.subscription)
        filter_object.words.add(word1)
        filter_object.words.add(word2)
        filter_object.save()
        filtered_entries = self.applyFilter(self.lj_channel, filter_object)
        self.assertEqual(2, len(filtered_entries))
        first_entry = filter(lambda x: x.title == first_title, filtered_entries)[0]
        second_entry = filter(lambda x: x.title == second_title, filtered_entries)[0]

        filter_object.condition_type = 'all'
        filtered_entries = self.applyFilter(self.lj_channel, filter_object)
        self.assertEqual(1, len(filtered_entries))
        self.assertEqual(filtered_entries[0].title, second_title)

        filter_object.filter_type = 'exclude'
        filtered_entries = self.applyFilter(self.lj_channel, filter_object)
        self.assertEqual(self.lj_channel.entries.count() - 1, len(filtered_entries))

        filter_object.condition_type = 'any'
        filtered_entries = self.applyFilter(self.lj_channel, filter_object)
        self.assertEqual(self.lj_channel.entries.count() - 2, len(filtered_entries))

    def testApplyExisting(self):
        """
        Applying the filter to existing entries.
        """
        word1 = models.Word.objects.create(name = FilterTest.morphology.getWordBase(u'selenium'))

        filter_object = models.Filter.objects.create(condition_type = 'any', filter_type = 'exclude', subscription = self.subscription)
        filter_object.words.add(word1)
        filter_object.save()
        old_message_count = self.subscription.message_set.count()
        self.subscription.applyFilter(filter_object)
        new_message_count = self.subscription.message_set.count()
        self.assertEqual(old_message_count - 1, new_message_count)

    def testApplyFilterThroughView(self):
        self.login(self.openid1)
        old_message_count = self.subscription.message_set.count()
        self.client.post('/filterEdit', {'tags' : u'', 'update' : u'on', 'filter_type' : 'exclude', 'condition_type' : 'all', 'words' : 'selenium', 'id' : '', 'subscription' : unicode(self.subscription.id) })
        new_message_count = self.subscription.message_set.count()
        self.assertEqual(old_message_count - 1, new_message_count)

class DeletionTest(FilledDbTestCase):
    def testMessageDeletion(self):
        self.login(self.openid1)
        response = self.client.post('/deleteMessage', { 'id' : self.google_message.id })
        self.assertEqual(response.status_code, 200)
        self.assertRaises(models.Message.DoesNotExist, models.Message.objects.get, id = self.google_message.id)

        response = self.client.post('/deleteMessage', { 'id' : self.yahoo_message.id })
        self.assertEqual(response.status_code, 404)
        models.Message.objects.get(id = self.yahoo_message.id)

    def testSubscriptionDeletion(self):
        '''
        Deletes only subscription, but not the messages in it.
        '''
        self.login(self.openid1)
        messages = list(self.feed_subscription1.message_set.all())
        response = self.client.post('/deleteSubscription', { 'id' : self.feed_subscription1.id, 'type' : 'subscription' })
        self.assertEqual(response.status_code, 200)
        self.assertRaises(models.Subscription.DoesNotExist, models.Subscription.objects.get, id = self.feed_subscription1.id)
        for id in map(lambda x: x.id, messages):
            models.Message.objects.get(id = id)

    def testSubscriptionDeletionAll(self):
        '''
        Deletes the subscripton and marks all the messages in it as ignored.
        '''
        self.login(self.openid1)
        messages = list(self.feed_subscription1.message_set.all())
        response = self.client.post('/deleteSubscription', { 'id' : self.feed_subscription1.id, 'type' : 'all_messages' })
        self.assertEqual(response.status_code, 200)
        self.assertRaises(models.Subscription.DoesNotExist, models.Subscription.objects.get, id = self.feed_subscription1.id)
        for id in map(lambda x: x.id, messages):
            self.assertEqual(models.Message.objects.get(id = id).ignored, True)

    def testSubscriptionDeletionThisOnly(self):
        '''
        Deletes the subscription and marks all the messages that occur only in this subscription as ignored.
        '''
        self.login(self.openid1)
        cur_message = self.feed_subscription1.message_set.all()[0]
        new_subscription = models.Subscription.objects.create(channel = self.codinghorror_channel, user = self.user1, name = 'new')
        cur_message.subscriptions.add(new_subscription)
        cur_message.save()
        new_message = models.Message.objects.create(user = self.user1, entry = self.yahoo_entry)
        new_message.subscriptions.add(self.feed_subscription1)
        new_message.save()

        messages = list(self.feed_subscription1.message_set.all())
        response = self.client.post('/deleteSubscription', { 'id' : self.feed_subscription1.id, 'type' : 'this_messages' })
        self.assertEqual(response.status_code, 200)
        self.assertRaises(models.Subscription.DoesNotExist, models.Subscription.objects.get, id = self.feed_subscription1.id)
        for id in map(lambda x: x.id, messages):
            self.assertEqual(models.Message.objects.get(id = id).ignored, id != cur_message.id)

    def testSubscriptionNoType(self):
        self.login(self.openid1)
        self.assertRaises(Exception, self.client.post, '/deleteSubscription', { 'id' : self.feed_subscription1.id})
